
#include "tsfile.h"
#include <string.h>
#include <stdlib.h>

#include <iostream>
#include <string>
using namespace std;

CTSFile::CTSFile(s8 * pFileName):CFile( pFileName)
{
	m_FileState 	= TSFileUnknow;

	m_FileSize 	= 0;
	m_nPacketSize = 0;
	m_PacketCount =0;
	Offset		=	0;


	OpenAndAnalyse();
}

CTSFile::~CTSFile(void)
{
}

void CTSFile::OpenAndAnalyse( )
{
	if(false == Open(CFile::OPEN_BIN_READ_AND_WRITE))
	{
		if(false == Open(CFile::OPEN_BIN_READ_ONLY))
		{
			m_FileState = TSFileOpenFailed;
			return;
		}
	}

	GetLenth(m_FileSize);
	
	if(false == Analyse())
		m_FileState = TSFileAnalyseFailed;
	else
		m_FileState = TSFileOK;
		
}


bool CTSFile::Analyse(void)
{
	//int 	TestTime;
	bool Ret	= false;
	Offset = 0;
	/*if( IsOtvMux())
	{
		AnalyseOtvHead();
	}
	*/
	return AnalyseAttribute();
}
/*
* name : AnalyseTSDataAttribute
* param : pFileData ,nFileSize 
* return : if analyse successed retrun ture or false.
* note : analyse out packet size and offset
*/
bool CTSFile::AnalyseAttribute(void)
{
	int 	TestTime;
	bool Ret	= false;
	//Offset = 0;
	u8 data;
	u32 os = Offset;
	u32	LastPart;
	for(int i =0; i <204 ; i++, os++)
	{
		GetByte(os, data);
		if(data == SYN_BYTE)
		{
			/*	try 188 packet size	*/
			for(TestTime=1; TestTime<PACKETS_NUMBER_TO_TRY_PACKET_SIZE ; TestTime++)
			{
				GetByte(os + 188* TestTime, data);
				if(data != SYN_BYTE)
					break;
			}
			if (TestTime == PACKETS_NUMBER_TO_TRY_PACKET_SIZE)
			{
				Ret = true;
				m_nPacketSize = 188;
				break;
			}
			/*	try 204 packet size	*/
			for(TestTime=1; TestTime<PACKETS_NUMBER_TO_TRY_PACKET_SIZE ; TestTime++)
			{
				GetByte(os + 204 * TestTime, data);
				if(data != SYN_BYTE)
					break;
			}
			if (TestTime == PACKETS_NUMBER_TO_TRY_PACKET_SIZE)
			{
				Ret = true;
				m_nPacketSize = 204;
				break;
			}
		}
	}
	if(Ret)
	{
		//pPacket.SetPktLenth(m_nPacketSize);
		m_PacketCount = (u32)((m_FileSize - os)/m_nPacketSize) ;
		LastPart = (u32)((m_FileSize - os) % m_nPacketSize );
		Offset = os;
	}
	return Ret;
}

void CTSFile::ReadPacket(CPacket * pp,u32 PacketIndex)
{

	Read((u8 *)(pp->GetPktData()), m_nPacketSize , Offset+PacketIndex * m_nPacketSize);

	pp->PacketSize = m_nPacketSize;
	pp->SetPktIdxInTs(PacketIndex);
}
/*
bool CTSFile::HardWritePacket(CPacket * pp)
{
	if(m_FileWritable)
	{
		Seek(Offset+pp->GetPktIdxInTs()* m_nPacketSize, CFile::begin);
		Write(pp->GetPktData(), m_nPacketSize);
		return true;
	}
	else
		return false;
}
bool CTSFile::SoftWritePacket(CPacket * pp)
{
	if(m_FileWritable)
	{
		u16 pid = GetPacketPID(pp->GetPktIdxInTs());
		if((pp->GetPID() == pid)||(STUFF_PID ==  pid))
			HardWritePacket(pp);
		else
		{
			u16 OffsetIdx = 0;

			while((STUFF_PID   != GetPacketPID(pp->GetPktIdxInTs() + (++OffsetIdx)))&&(OffsetIdx < SOFTSIZE));
			
			if(OffsetIdx < SOFTSIZE)
			{
				Seek(Offset+(pp->GetPktIdxInTs() + OffsetIdx)* m_nPacketSize, CFile::begin);
				Write(pp->GetPktData(), m_nPacketSize);
				pp->PktIdxInTs += OffsetIdx;
			}
			else
			{
				TRACE("Find next stuff packet failed !!!!!");
				HardWritePacket(pp);
			}
		}
		return true;
	}
	else
		return false;
}

*/
bool CTSFile::TraceTsfileState()
{
	printf("file:%s . lenth: %d. \n", m_FileName, m_FileSize);
	switch(m_FileState)
	{
		default:
		case TSFileUnknow:
			cout<< "unknow error" << endl;
			break;
		case TSFileOpenFailed:
			cout<<  "file open failed" << endl;
			break;
		case TSFileAnalyseFailed:
			cout<<  "file analyse failed" << endl;
			break;
		case TSFileOK:
			cout<<  "ts file ok \n" << endl;
			return true;
	}
	return false	;
}

u8 	CTSFile::GetPacketSize()
{
	return m_nPacketSize;
}
u32 	CTSFile::GetPacketCount()
{
	return m_PacketCount;
}


/*
	u8 syn_byte						:8 ;

	u8 PID_hi						:5 ;
	u8 transport_priority				:1 ;
	u8 payload_unit_start_indicator	:1 ;
	u8 transport_error_indicator		:1 ;
	
	u8 PID_low						:8;
bool CTSFile::SetPacketPID(u32 PacketIndex, u16 NewPid)
{
	u8 data[2];
	if(m_FileWritable)
	{
		Seek(Offset+PacketIndex * m_nPacketSize+1, CFile::begin);
		Read(data , 2);

		data[0] = (data[0] & 0xE0) | (NewPid>>8);
		data[1] = NewPid & 0xFF;
		Seek(Offset+PacketIndex * m_nPacketSize+1, CFile::begin);
		Write(data , 2);
		return true;
	}
	else
		return false;
}
*/

u16 CTSFile::GetPacketPID(u32 PacketIndex)
{
	u8 data1, data2;

	GetByte(Offset+PacketIndex * m_nPacketSize+1, data1);
	GetByte(Offset+PacketIndex * m_nPacketSize+2, data1);	

	return (((data1) & 0x1F)*256 + data2);
}

bool CTSFile::IsValid(void)
{
	if(m_FileState == TSFileOK)
	{
		/*if((m_nPacketSize == 0)||(m_PacketCount == 0))
		{
			if(AnalyseAttribute())
			{
				m_FileState = TSFileReady;
				return true;
			}
			else
			{
				m_FileState = TSFileError;
				return false;
			}
		}*/
		return true;
	}
	else
		return false;
}
/*

bool CTSFile::IsOtvMux()
{
	if( (GetByte(0) == 'O') &&(GetByte(1) == 'T') &&(GetByte(2) == 'V') &&
		(GetByte(3) == ' ') &&
		(GetByte(4) == ':') &&(GetByte(5) == '-') &&(GetByte(6) == ')'))
	{
		return true;
	}
	else
	{
		return false;
	}
}
bool CTSFile::AnalyseOtvHead()
{
	//Offset += 0xc7c;
	char cb;
	Offset = 0;
	u32 Offset2;
	while(1)
	{
		Offset2 = Offset;
		while( GetByte(Offset2++)  == 0);

		if((Offset2 - Offset) >10 )//	more than 10 0	
		{
			Offset = Offset2-1;
			break;
		}
		
		cb = GetByte(Offset) ;
		
		Offset++;

		if(cb == 0 )
			m_FileErrorStr.AppendFormat("\r\n");
		else if(cb < 32 )//		the charactor befor 32 is control code	
			m_FileErrorStr.AppendFormat("'%02x'", cb);
		else
			m_FileErrorStr.AppendFormat("%c", cb);
	}
	m_FileErrorStr.AppendFormat("\r\n");
	return true;
}
*/


bool CTSFile::FindForwardSection(u32 & CurIdx, u16 pid ,u16	tableid)
{
	CPacket  pPkt ;
	CommonSection * pPS; 

	while(CurIdx < m_PacketCount)
	{
		CurIdx ++;
		ReadPacket(&pPkt, CurIdx);
		if((pid == pPkt.GetPID() )&& pPkt.IsUnitStart())
		{
			pPS = pPkt.GetSectionAddress();
			if(pPS->table_id == tableid)
			{
				return true;
			}
		}
	}
	return false;
}


CSection * CTSFile::BuildNextSection(u32 & CurIdx, u16 pid  ,u16	tableid)
{
	u32 NeedCopyCount ;//  , SecBuffLen;
	CPacket  Pkt ;
	
	if(false == FindForwardSection(CurIdx, pid ,	tableid))
		return NULL;
	
	ReadPacket(&Pkt, CurIdx);
	u8	PktSize = Pkt.GetPktSize();
	CommonSection * pPS = Pkt.GetSectionAddress();
	
	NeedCopyCount = (pPS->section_length_hi*256+pPS->section_length_low) + 3 ;	
	/*	section length only	indicat data lenth after this field, so +3 */
	//return NULL;
	assert(NeedCopyCount < 4096);
	CSection * pSec = new CSection;

	if(!pSec || ((pSec->SectionData =  (u8 *)malloc(NeedCopyCount)) == NULL))
	{
		printf("Malloc(%d) section data fail\r\n",NeedCopyCount);
		delete pSec;
		assert(0);
		return NULL;
	}
	//pSec->StartPktIdx = CurIdx;
		
	//NeedCopyCount = SecBuffLen;
	
	if(Pkt.GetDataStartOffset() + NeedCopyCount < (PktSize))
	{/* this section in one Packet	*/
		memcpy(pSec->SectionData , pPS ,NeedCopyCount);
	}
	else
	{/*	this section transmited in more than one Packet	*/
		u8 * BuffAddr = pSec->SectionData;
		u8 CurCpy;
		memcpy(BuffAddr , pPS , (PktSize - Pkt.GetDataStartOffset()));
		NeedCopyCount -= (PktSize - Pkt.GetDataStartOffset());
		BuffAddr += (PktSize - Pkt.GetDataStartOffset());
		while((NeedCopyCount > 0) && (CurIdx < m_PacketCount))
		{
			CurIdx ++;
			ReadPacket(&Pkt, CurIdx);
			if((NeedCopyCount + PACKET_HEAD_SIZE) > (PktSize ))
				CurCpy = (PktSize - PACKET_HEAD_SIZE);
			else
				CurCpy = (u8)NeedCopyCount;
			memcpy(BuffAddr , ((u8 *)(Pkt.GetPktData()))+ PACKET_HEAD_SIZE ,CurCpy);
			BuffAddr += CurCpy;
			NeedCopyCount -= CurCpy;/* may be copy more than we want */
		}

		if(NeedCopyCount > 0)
		{
			printf("section data unintegreted on pkt %d \r\n",CurIdx);
			delete pSec;
			return NULL;
		}
	}
	return pSec;
}

bool CTSFile::BuildTable(CTable	& pTbl )
{
	bool BltRst = false;
	CSection * pSec;

	u32		PktIdx = 0;

	pTbl.ReleaseSection();
	
	while(PktIdx < (s32)m_PacketCount)// current index is not last index
	{
		if(pSec = BuildNextSection(PktIdx, pTbl.GetPID(),pTbl.GetTableID()))
		{
			pTbl.AttachSection(pSec);
			if(pTbl.IsIntegrity())
			{
				pTbl.UpDateVersion();
				pTbl.SortSection();
				BltRst = true;
				break;
			}
		}
		else
		{
			break;
		}
	}
	return BltRst; /* build successed out	*/
}
